package com.ls.controller.advice;

import com.alibaba.fastjson.JSON;
import com.ls.util.BizCodeEnum;
import com.ls.util.CommunityConstant;
import com.ls.util.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * 统一处理异常类 @ControllerAdvice(annotations = Controller.class)
 * 只处理带 @Controller 注解的类
 *
 * @author ls
 * @date 2021/1/3
 **/
@ControllerAdvice(annotations = Controller.class)
public class GlobalExceptionAdvice {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionAdvice.class);

    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public R handleValidException(BindException e) {
        Map<String, Object> map = new HashMap<>();
        // 获取错误校验的结果
        e.getFieldErrors().forEach(item -> {
            // 错误属性
            String field = item.getField();
            // 错误提示
            String message = item.getDefaultMessage();
            map.put(field, message);
        });
        R error = R.error(BizCodeEnum.VALID_EXCEPTION);
        error.putAll(map);
        return error;
    }

    /**
     * 处理 MethodArgumentNotValidException 异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public R handleValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        Map<String, Object> map = new HashMap<>();
        // 获取错误校验的结果
        bindingResult.getFieldErrors().forEach(item -> {
            // 错误属性
            String field = item.getField();
            // 错误提示
            String message = item.getDefaultMessage();
            map.put(field, message);
        });
        R error = R.error(BizCodeEnum.VALID_EXCEPTION);
        error.putAll(map);
        return error;
    }


    /**
     * 用于修饰方法,该方法会在Controller出现异常后被调用,用于处理捕获到的异常。
     *
     * @param e        在 Controller 捕获到的异常
     * @param request
     * @param response
     * @throws IOException
     */
    @ExceptionHandler({Exception.class})
    public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.error("服务器发生异常: {}", e.getMessage());
        for (StackTraceElement element : e.getStackTrace()) {
            logger.error(element.toString());
        }

        String xRequestedWith = request.getHeader("x-requested-with");
        // 异步请求, 相应json字符串
        if (CommunityConstant.XML_HTTP_REQUEST.equals(xRequestedWith)) {
            response.setContentType("application/json;charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.write(JSON.toJSONString(R.error(BizCodeEnum.UNKNOWN_EXCEPTION)));
        } else {
            // 重定向到错误页面
            response.sendRedirect(request.getContextPath() + "/error");
        }
    }

}
